package com.restkeeper.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.restkeeper.aop.TenantAnnotation;
import com.restkeeper.dto.*;
import com.restkeeper.entity.OrderDetailEntity;
import com.restkeeper.entity.OrderEntity;
import com.restkeeper.entity.OrderViewEntity;
import com.restkeeper.exception.BussinessException;
import com.restkeeper.lock.CalculationBusinessLock;
import com.restkeeper.mapper.OrderMapper;
import com.restkeeper.mapper.OrderViewMapper;
import com.restkeeper.print.Print;
import com.restkeeper.print.PrintOrder;
import com.restkeeper.print.PrinterDish;
import com.restkeeper.sequence.SequenceUtils;
import com.restkeeper.store.entity.*;
import com.restkeeper.store.service.*;
import com.restkeeper.tenant.TenantContext;
import com.restkeeper.utils.DateTimeUtils;
import com.restkeeper.utils.OrderDetailType;
import com.restkeeper.utils.OrderPayType;
import com.restkeeper.utils.SystemCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单主表 服务实现类  ok
 * </p>
 */
@Service(version = "1.0.0", protocol = "dubbo")
@Component
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements IOrderService {

    @Autowired
    private IOrderDetailService orderDetailService;

    @Reference(version = "1.0.0",check = false)
    private ISetmealService setmealService;

    @Reference(version = "1.0.0",check = false)
    private IDishService dishService;


    @Reference(version = "1.0.0",check = false)
    private ISellCalculationService sellCalculationService;

    @Reference(version = "1.0.0",check = false)
    private ITableService tableService;

    @Reference(version = "1.0.0",check = false)
    private ITableLogService tableLogService;

    @Reference(version = "1.0.0",check = false)
    private IDishCategoryService dishCategoryService;

    @Autowired
    private CalculationBusinessLock lock;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    OrderViewMapper orderViewMapper;

    private static final String orderRedisKeyPrefix = "table-order-";


    @Override
    @Transactional(rollbackFor = {Exception.class})
    @TenantAnnotation
    public String addOrder(OrderEntity orderEntity) {
        if(StringUtils.isEmpty(orderEntity.getOrderNumber())){
            //流水号多租户支持
            String storeId = RpcContext.getContext().getAttachment("storeId");
            orderEntity.setOrderNumber(SequenceUtils.getSequence(storeId));
        }
        this.saveOrUpdate(orderEntity);

        List<OrderDetailEntity> orderDetailEntities = orderEntity.getOrderDetails();
        Print backPrint = new Print();
        orderDetailEntities.forEach(orderDetailEntity -> {
            //沽清检查
            Integer remainder = sellCalculationService.getRemainderCount(orderDetailEntity.getDishId());
            if(remainder!=-1){
                if(remainder<orderDetailEntity.getDishNumber()){
                    throw new BussinessException(orderDetailEntity.getDishName()+"超过沽清设置数目");
                }
                //沽清
                sellCalculationService.decrease(orderDetailEntity.getDishId(),orderDetailEntity.getDishNumber());
            }
            orderDetailEntity.setOrderId(orderEntity.getOrderId());
            orderDetailEntity.setOrderNumber(SequenceUtils.getSequenceWithPrefix(orderEntity.getOrderNumber()));
            //统计时候需要知道分类信息
            String categoryName="";
            if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_MORMAL){
                Dish dish = dishService.getById(orderDetailEntity.getDishId());
                System.out.println("dish------------- "+dish+" order"+orderDetailEntity);
                DishCategory dishCategory= dishCategoryService.getById(dish.getCategoryId());
                if(dishCategory!=null){
                    categoryName = dishCategory.getName();
                }
            }else if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_SETMEAL){
                Setmeal setmeal = setmealService.getById(orderDetailEntity.getDishId());
                DishCategory dishCategory= dishCategoryService.getById(setmeal.getCategoryId());
                if(dishCategory!=null){
                    categoryName = dishCategory.getName();
                }
            }
            orderDetailEntity.setDishCategoryName(categoryName);
            List<String> dishIds = Lists.newArrayList();
            dishIds.add(orderDetailEntity.getDishId());

            backPrint.setFront(false);
            backPrint.setPrintType(SystemCode.PRINT_MADE_MENU);
            backPrint.setDishIdes(dishIds);
            backPrint.setDishNumber(orderDetailEntity.getDishNumber());
            backPrint.setStoreId(orderDetailEntity.getStoreId());
            backPrint.setShopId(orderDetailEntity.getShopId());
        });
        orderDetailService.saveBatch(orderDetailEntities);
        //后厨打印
        rabbitTemplate.convertAndSend(SystemCode.PRINTER_EXCHANGE_NAME, JSON.toJSONString(backPrint));
        //收银端打印
        print(SystemCode.PRINT_BEFOREHAND, orderEntity,true);
        return orderEntity.getOrderId();
    }

    /**
     * 打印
     */
    private void print(int printType,OrderEntity orderEntity,boolean isFront) {
        String shopId = TenantContext.getShopId();
        String storeId = TenantContext.getStorId();
        Print print = new Print();
        print.setShopId(shopId);
        print.setStoreId(storeId);
        print.setFront(isFront);
        print.setPrintOrder(buidPrintOrder(orderEntity));
        print.setPrintType(printType);
        String printJson = JSON.toJSONString(print);
        log.info("print-info:"+printJson);
        //收银端打印
        rabbitTemplate.convertAndSend(SystemCode.PRINTER_EXCHANGE_NAME, printJson);
    }

//    @Override
//    @Transactional(rollbackFor = {Exception.class})
//    @TenantAnnotation
//    public String addOrder(OrderEntity orderEntity) {
//        if(StringUtils.isEmpty(orderEntity.getOrderNumber())){
//            //流水号多租户支持
//            String storeId = RpcContext.getContext().getAttachment("storeId");
//            orderEntity.setOrderNumber(SequenceUtils.getSequence(storeId));
//        }
//        this.saveOrUpdate(orderEntity);
//
//        //收银端打印
//        print(SystemCode.PRINT_BEFOREHAND,orderEntity.getOrderId(),true);
//
////        String shopId = TenantContext.getShopId();
////        String storeId = TenantContext.getStorId();
//
//        List<OrderDetailEntity> orderDetailEntities = orderDetailService.getDetailsByOrderId(orderEntity.getOrderId());
//        if(orderDetailEntities == null)
//            orderDetailEntities = Lists.newArrayList();
//        orderDetailEntities.forEach(orderDetailEntity -> {
//            //沽清检查
////            TenantContext.addAttachment("shopId",shopId);
////            TenantContext.addAttachment("storeId",storeId);
//            Integer remainder = sellCalculationService.getRemainderCount(orderDetailEntity.getDishId());
//            if(remainder!=-1){
//               if(remainder<orderDetailEntity.getDishNumber()){
//                   throw new BussinessException(orderDetailEntity.getDishName()+"超过沽清设置数目");
//               }
//                //沽清
//                sellCalculationService.decrease(orderDetailEntity.getDishId(),orderDetailEntity.getDishNumber());
//            }
//            orderDetailEntity.setOrderId(orderEntity.getOrderId());
//            orderDetailEntity.setOrderNumber(SequenceUtils.getSequenceWithPrefix(orderEntity.getOrderNumber()));
//            log.info("dish Id:"+orderDetailEntity.getDishId() +" dishtype "+orderDetailEntity.getDishType());
//            //统计时候需要知道分类信息
//            String categoryName="";
//            if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_MORMAL){
//                Dish dish = dishService.getById(orderDetailEntity.getDishId());
//                DishCategory dishCategory= dishCategoryService.getById(dish.getCategoryId());
//                if(dishCategory!=null){
//                    categoryName = dishCategory.getName();
//                }
//            }else if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_SETMEAL){
//                Setmeal setmeal = setmealService.getById(orderDetailEntity.getDishId());
//                DishCategory dishCategory= dishCategoryService.getById(setmeal.getCategoryId());
//                if(dishCategory!=null){
//                    categoryName = dishCategory.getName();
//                }
//            }
//            orderDetailEntity.setDishCategoryName(categoryName);
//            List<String> dishIds = Lists.newArrayList();
//            dishIds.add(orderDetailEntity.getDishId());
//
//            print(SystemCode.PRINT_RETURN_DISH,orderEntity.getOrderId(),false);
//        });
//        orderDetailService.saveBatch(orderDetailEntities);
//
//        return orderEntity.getOrderId();
//    }


    /**
     * 换桌
     * @param tableId
     * @param targetTableId
     * @return
     */
    @Override
    @TenantAnnotation
    @Transactional(rollbackFor = {Exception.class})
    public boolean changeTable(String tableId, String targetTableId) {
        Table targetTable= tableService.getById(targetTableId);
        if(targetTable==null){
            throw new BussinessException("桌台不存在");
        }
        //查看目标桌台是否空闲
        if(targetTable.getStatus()!=SystemCode.TABLE_STATUS_FREE){
            throw new BussinessException("桌台非空闲状态，不能换桌");
        }

        Table sourceTable = tableService.getById(tableId);
        //原来桌台设置为空闲
        sourceTable.setStatus(SystemCode.TABLE_STATUS_FREE);
        tableService.updateById(sourceTable);
        //目标桌台设置为开桌状态
        targetTable.setStatus(SystemCode.TABLE_STATUS_OPEND);
        tableService.updateById(targetTable);
        int personNumber=0;
        OrderEntity orderEntity = getNoPayOrder(tableId);
        if(orderEntity==null){
            //没有下单,开桌人数从开桌日志获取
            TableLog log = tableLogService.getOpenTableLog(tableId);
            if(log!=null){
                personNumber = log.getUserNumbers();
            }
        }else{
            personNumber =orderEntity.getPersonNumbers();
        }
        //新增开桌日志
        TableLog tableLog =new TableLog();
        tableLog.setTableStatus(SystemCode.TABLE_STATUS_OPEND);
        tableLog.setCreateTime(LocalDateTime.now());
        tableLog.setTableId(targetTableId);
        tableLog.setUserNumbers(personNumber);
        tableLogService.save(tableLog);
        //修改订单桌台关系
        orderEntity.setTableId(targetTableId);
        return this.updateById(orderEntity);
    }

    /**
     * 修改人数
     * @param tableId
     * @param number
     * @return
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean changeNumber(String tableId, Integer number){
        OrderEntity orderEntity = getNoPayOrder(tableId);
        if(orderEntity==null){
            //下单前
            TableLog log = tableLogService.getOpenTableLog(tableId);
            if(log==null){
                throw new BussinessException("换桌前没有开桌");
            }
            log.setUserNumbers(number);
            tableLogService.saveOrUpdate(log);
        }else{
            orderEntity.setPersonNumbers(number);
            this.updateById(orderEntity);
        }
       return  true;
    }


//    @Override
//    public boolean plusDish(OrderDetailEntity orderDetailEntity) {
//        return orderDetailService.save(orderDetailEntity);
//    }

//    /**
//     * 加菜
//     * @param plusDishDTO
//     * @return
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean plusDish(PlusDishDTO plusDishDTO) {
//        String shopId = RpcContext.getContext().getAttachment("shopId");
//        String storeId = RpcContext.getContext().getAttachment("storeId");
//        String redisKey = orderRedisKeyPrefix+"-"+shopId+"-"+storeId+plusDishDTO.getTableId();
//        OrderEntity orderEntity = null;
//
//        if(!redisTemplate.hasKey(redisKey)){
//            orderEntity = new OrderEntity();
//            orderEntity.setCreateTime(LocalDateTime.now());
//            orderEntity.setOperatorName(plusDishDTO.getOperatorName());
//            orderEntity.setPayStatus(SystemCode.ORDER_STATUS_NOPAY);
//            orderEntity.setOrderNumber(IdWorker.getIdStr());
//            orderEntity.setRemark(plusDishDTO.getRemark());
//            this.save(orderEntity);
//            redisTemplate.opsForValue().set(redisKey,orderEntity.getOrderId(),1,TimeUnit.DAYS);
//        }
//
//        String orderId = redisTemplate.opsForValue().get(redisKey);
//        String orderNumber = orderEntity.getOrderNumber();
//        plusDishDTO.getDishDTOList()
//                .forEach(d->{
//                    //设置订单详情
//                    Dish dish = dishService.getById(d.getDishId());
//
//                    String key = shopId+storeId+d.getDishId()+d.getDishType();
//                    boolean lockSuccess = lock.getLock(key,10,()->sellCalculationService.getRemainderCount(d.getDishId()));
//                    if(!lockSuccess) throw new BussinessException(dish.getName()+"已沽清");
//                    try {
//                        OrderDetailEntity orderDetailEntity = new OrderDetailEntity();
//                        orderDetailEntity.setTableId(plusDishDTO.getTableId());
//                        orderDetailEntity.setOrderId(orderId);
//                        orderDetailEntity.setOrderNumber(orderNumber);
//                        orderDetailEntity.setDiscountRemark(d.getDiscountRemark());
//                        orderDetailEntity.setDishRemark(d.getDishRemark());
//                        orderDetailEntity.setDetailStatus(5);
//                        orderDetailEntity.setFlavorRemark(d.getFlavorRemark());
//                        orderDetailEntity.setDishNumber(d.getDishNumber());
//                        orderDetailEntity.setDishType(d.getDishType());
//                        orderDetailEntity.setPresentRemark(d.getPresentRemark());
//                        if(d.getDishType() == SystemCode.DISH_TYPE_MORMAL){
//                            orderDetailEntity.setDishName(dish.getName());
//                            orderDetailEntity.setDishPrice(dish.getPrice());
//                            orderDetailEntity.setDishAmount(d.getDishNumber()*dish.getPrice());
//                        }else {
//                            Setmeal setmeal = setmealService.getById(d.getDishId());
//                            orderDetailEntity.setDishName(setmeal.getName());
//                            orderDetailEntity.setDishPrice(setmeal.getPrice());
//                            orderDetailEntity.setDishAmount(d.getDishNumber()*setmeal.getPrice());
//                        }
//                        sellCalculationService.decrease(d.getDishId(),d.getDishNumber());
//                        orderDetailService.save(orderDetailEntity);
//                    }finally {
//                        lock.unlock(key);
//                    }
//
//                });
//
//        return true;
//    }

    /**
     * 加菜
     * @param
     * @return
     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean plusDish(PlusDishDTO plusDishDTO) {
//        String shopId = RpcContext.getContext().getAttachment("shopId");
//        String storeId = RpcContext.getContext().getAttachment("storeId");
//        String redisKey = orderRedisKeyPrefix+"-"+shopId+"-"+storeId+plusDishDTO.getTableId();
//        OrderEntity orderEntity = null;
//
//        if(!redisTemplate.hasKey(redisKey)){
//            orderEntity = new OrderEntity();
//            orderEntity.setCreateTime(LocalDateTime.now());
//            orderEntity.setOperatorName(plusDishDTO.getOperatorName());
//            orderEntity.setPayStatus(SystemCode.ORDER_STATUS_NOPAY);
//            orderEntity.setOrderNumber(IdWorker.getIdStr());
//            orderEntity.setOrderRemark(plusDishDTO.getRemark());
//            this.save(orderEntity);
//            redisTemplate.opsForValue().set(redisKey,orderEntity.getOrderId(),1,TimeUnit.DAYS);
//        }
//
//        String orderId = redisTemplate.opsForValue().get(redisKey);
//        String orderNumber = orderEntity.getOrderNumber();
//        plusDishDTO.getDishDTOList()
//                .forEach(d->{
//                    //设置订单详情
//                    Dish dish = dishService.getById(d.getDishId());
//
////                    String key = shopId+storeId+d.getDishId()+d.getDishType();
////                    boolean lockSuccess = lock.getLock(key,10,()->sellCalculationService.getRemainderCount(d.getDishId()));
////                 if(!lockSuccess) throw new BussinessException(dish.getName()+"已沽清");
//                        OrderDetailEntity orderDetailEntity = new OrderDetailEntity();
//                        orderDetailEntity.setTableId(plusDishDTO.getTableId());
//                        orderDetailEntity.setOrderId(orderId);
//                        orderDetailEntity.setOrderNumber(orderNumber);
//                        orderDetailEntity.setDiscountRemark(d.getDiscountRemark());
//                        orderDetailEntity.setDishRemark(d.getDishRemark());
//                        orderDetailEntity.setDetailStatus(5);
//                        orderDetailEntity.setFlavorRemark(d.getFlavorRemark());
//                        orderDetailEntity.setDishNumber(d.getDishNumber());
//                        orderDetailEntity.setDishType(d.getDishType());
//                        orderDetailEntity.setPresentRemark(d.getPresentRemark());
//                        if(d.getDishType() == SystemCode.DISH_TYPE_MORMAL){
//                            orderDetailEntity.setDishName(dish.getName());
//                            orderDetailEntity.setDishPrice(dish.getPrice());
//                            orderDetailEntity.setDishAmount(d.getDishNumber()*dish.getPrice());
//                        }else {
//                            Setmeal setmeal = setmealService.getById(d.getDishId());
//                            orderDetailEntity.setDishName(setmeal.getName());
//                            orderDetailEntity.setDishPrice(setmeal.getPrice());
//                            orderDetailEntity.setDishAmount(d.getDishNumber()*setmeal.getPrice());
//                        }
//                        sellCalculationService.decrease(d.getDishId(),d.getDishNumber());
//                        orderDetailService.save(orderDetailEntity);
//                });
//        return true;
//    }


//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean plusDish(PlusDishDTO plusDishDTO) {
//        String shopId = RpcContext.getContext().getAttachment("shopId");
//        String storeId = RpcContext.getContext().getAttachment("storeId");
//        String redisKey = orderRedisKeyPrefix+"-"+shopId+"-"+storeId+plusDishDTO.getTableId();
//        OrderEntity orderEntity = null;
//
//        if(!redisTemplate.hasKey(redisKey)){
//            orderEntity = new OrderEntity();
//            orderEntity.setCreateTime(LocalDateTime.now());
//            orderEntity.setOperatorName(plusDishDTO.getOperatorName());
//            orderEntity.setPayStatus(SystemCode.ORDER_STATUS_NOPAY);
//            orderEntity.setOrderNumber(IdWorker.getIdStr());
//            orderEntity.setOrderRemark(plusDishDTO.getRemark());
//            this.save(orderEntity);
//            redisTemplate.opsForValue().set(redisKey,orderEntity.getOrderId(),1,TimeUnit.DAYS);
//        }
//
//        String orderId = redisTemplate.opsForValue().get(redisKey);
//        String orderNumber = orderEntity.getOrderNumber();
//        plusDishDTO.getDishDTOList()
//                .forEach(d->{
//                    //设置订单详情
//                    Dish dish = dishService.getById(d.getDishId());
//
////                    String key = shopId+storeId+d.getDishId()+d.getDishType();
////                    boolean lockSuccess = lock.getLock(key,10,()->sellCalculationService.getRemainderCount(d.getDishId()));
////                 if(!lockSuccess) throw new BussinessException(dish.getName()+"已沽清");
//                    OrderDetailEntity orderDetailEntity = new OrderDetailEntity();
//                    orderDetailEntity.setTableId(plusDishDTO.getTableId());
//                    orderDetailEntity.setOrderId(orderId);
//                    orderDetailEntity.setOrderNumber(orderNumber);
//                    orderDetailEntity.setDiscountRemark(d.getDiscountRemark());
//                    orderDetailEntity.setDishRemark(d.getDishRemark());
//                    orderDetailEntity.setDetailStatus(5);
//                    orderDetailEntity.setFlavorRemark(d.getFlavorRemark());
//                    orderDetailEntity.setDishNumber(d.getDishNumber());
//                    orderDetailEntity.setDishType(d.getDishType());
//                    orderDetailEntity.setPresentRemark(d.getPresentRemark());
//                    if(d.getDishType() == SystemCode.DISH_TYPE_MORMAL){
//                        orderDetailEntity.setDishName(dish.getName());
//                        orderDetailEntity.setDishPrice(dish.getPrice());
//                        orderDetailEntity.setDishAmount(d.getDishNumber()*dish.getPrice());
//                    }else {
//                        Setmeal setmeal = setmealService.getById(d.getDishId());
//                        orderDetailEntity.setDishName(setmeal.getName());
//                        orderDetailEntity.setDishPrice(setmeal.getPrice());
//                        orderDetailEntity.setDishAmount(d.getDishNumber()*setmeal.getPrice());
//                    }
//                    sellCalculationService.decrease(d.getDishId(),d.getDishNumber());
//                    orderDetailService.save(orderDetailEntity);
//                });
//        return true;
//    }

    @Override
    public OrderEntity getNoPayOrder(String tableId) {
        QueryWrapper<OrderEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_NOPAY)
                .eq(OrderEntity::getOrderSource,SystemCode.ORDER_SOURCE_STORE)
                .eq(OrderEntity::getTableId,tableId)
                .orderByDesc(OrderEntity::getCreateTime);
       List<OrderEntity> orderEntityList= this.list(wrapper);
        if(orderEntityList==null||orderEntityList.isEmpty()){
            return null;
        }
        OrderEntity orderEntity = orderEntityList.get(0);
        orderEntity.setOrderDetails(orderDetailService.getDetailsByOrderId(orderEntity.getOrderId()));
      //  orderDetailEntityList.addAll(orderDetailService.getDetailsByOrderId(orderEntity.getOrderId()));
        //if(orderEntityList == null || orderEntityList.size()<=0) return null;

//        List<OrderDetailEntity> orderDetailEntityList = Lists.newArrayList();
//        for (OrderEntity orderEntity : orderEntityList) {
//            orderDetailEntityList.addAll(orderDetailService.getDetailsByOrderId(orderEntity.getOrderId()));
//        }
//        orderEntityList.stream()
//                     .forEach(d->d.getOrderDetails().forEach(details->orderDetailEntityList.add(details)));

        return orderEntity;
    }

    @Override
    public boolean hasNoPay(String tableId) {
        QueryWrapper<OrderEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_NOPAY)
                .eq(OrderEntity::getTableId,tableId)
                .eq(OrderEntity::getOrderSource,SystemCode.ORDER_SOURCE_STORE);

        return this.count(wrapper) > 0;
    }



    /**
     * 退菜
     * @param orderDetailEntity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean returnDish(OrderDetailEntity orderDetailEntity) {
      //  String key = shopId+storeId+orderDetailEntity.getDishId()+orderDetailEntity.getDishType();
       // lock.spinLock(key,()->1);
        String storeId = RpcContext.getContext().getAttachment("storeId");
        //多租户支持
        String orderNumber = SequenceUtils.getSequence(storeId);
        QueryWrapper<OrderDetailEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                    .eq(OrderDetailEntity::getOrderId,orderDetailEntity.getOrderId())
                    .eq(OrderDetailEntity::getDishId,orderDetailEntity.getDishId());
        int count = orderDetailService.list(wrapper).stream().mapToInt(o-> o.getDishNumber()).sum();
        if(count <= 0) throw new BussinessException("该菜品或套餐已经被退完");
        orderDetailEntity.setDishNumber(-1);
        orderDetailEntity.setOrderNumber(orderNumber);
        printReturnDish(orderDetailEntity.getDishId());

        return orderDetailService.save(orderDetailEntity);
    }


    /**
     * 退菜
     * @param detailDTO
     * @return
     */
    @Override
    @TenantAnnotation
    @Transactional(rollbackFor = Exception.class)
    public boolean returnDish(DetailDTO detailDTO) {
         OrderDetailEntity detailEntity = orderDetailService.getById(detailDTO.getDetailId());
         int dishStatus = detailEntity.getDetailStatus();
         if(OrderDetailType.PLUS_DISH.getType()==dishStatus||OrderDetailType.NORMAL_DISH.getType()==dishStatus){
             if(detailEntity.getDishNumber()<=0){
                 throw new BussinessException(detailEntity.getDishName()+"已经被退完");
             }
             //多租户支持
             OrderDetailEntity retrun_detailEntity=new OrderDetailEntity();
             BeanUtils.copyProperties(detailEntity,retrun_detailEntity);
             //去掉多余copy字段
             retrun_detailEntity.setDetailId(null);
             retrun_detailEntity.setOrderNumber(SequenceUtils.getSequenceWithPrefix(detailEntity.getOrderNumber()));
             retrun_detailEntity.setDetailStatus(OrderDetailType.RETURN_DISH.getType());
             retrun_detailEntity.setDishNumber(1);
             retrun_detailEntity.setDishAmount(detailEntity.getDishPrice());
             retrun_detailEntity.setReturnRemark(detailDTO.getRemarks().toString());
             //多租户让mybatis-plus自己处理，否者报重复字段错误
             retrun_detailEntity.setStoreId(null);
             retrun_detailEntity.setShopId(null);
             orderDetailService.save(retrun_detailEntity);
             //修改以前订单
             detailEntity.setDishNumber(detailEntity.getDishNumber()-1);
             detailEntity.setDishAmount(detailEntity.getDishNumber()*detailEntity.getDishPrice());
             orderDetailService.updateById(detailEntity);

             //修改订单主表信息
             OrderEntity orderEntity = this.getById(detailEntity.getOrderId());
             orderEntity.setTotalAmount(orderEntity.getTotalAmount()-detailEntity.getDishPrice());

             //沽清+1
             sellCalculationService.add(detailEntity.getDishId(),1);

             printReturnDish(detailEntity.getDishId());
         }else{
             throw new BussinessException("不支持退菜操作");
         }
        return true;
    }

    @Override
    @TenantAnnotation
    @Transactional(rollbackFor = Exception.class)
    public boolean presentDish(DetailDTO detailDTO){
        OrderDetailEntity detailEntity = orderDetailService.getById(detailDTO.getDetailId());
        int dishStatus = detailEntity.getDetailStatus();
        if(OrderDetailType.PLUS_DISH.getType()==dishStatus||OrderDetailType.NORMAL_DISH.getType()==dishStatus){
            if(detailEntity.getDishNumber()<=0){
                throw new BussinessException("该菜品或套餐已经赠送完");
            }
            String storeId = RpcContext.getContext().getAttachment("storeId");
            //多租户支持
            String orderNumber = SequenceUtils.getSequence(storeId);
            OrderDetailEntity present_detailEntity=new OrderDetailEntity();
            BeanUtils.copyProperties(detailEntity,present_detailEntity);
            present_detailEntity.setDetailId(null);
            present_detailEntity.setOrderNumber(orderNumber);
            present_detailEntity.setDetailStatus(OrderDetailType.PRESENT_DISH.getType());
            present_detailEntity.setDishNumber(1);
            present_detailEntity.setDishAmount(detailEntity.getDishPrice());
            present_detailEntity.setDishRemark(detailDTO.getRemarks().toString());
            //多租户让mybatis-plus自己处理，否者报重复字段错误
            present_detailEntity.setStoreId(null);
            present_detailEntity.setShopId(null);
            orderDetailService.save(present_detailEntity);
            //修改以前订单
            detailEntity.setDishNumber(detailEntity.getDishNumber()-1);
            detailEntity.setDishAmount(detailEntity.getDishNumber()*detailEntity.getDishPrice());
            orderDetailService.updateById(detailEntity);
            //修改主订单
            OrderEntity orderEntity= this.getById(detailEntity.getOrderId());
            orderEntity.setPresentAmount(orderEntity.getPresentAmount()+present_detailEntity.getDishAmount());
        }else{
            throw new BussinessException("不支持赠菜操作");
        }
        return true;
    }



    @Override
    @TenantAnnotation
    public boolean pay(OrderEntity orderEntity) {
//        String shopId = RpcContext.getContext().getAttachment("shopId");
//        String storeId = RpcContext.getContext().getAttachment("storeId");
        //向消息队列发消息
//        OrderMsgDTO msg = new OrderMsgDTO();
//        msg.setOrderId(orderEntity.getOrderId());
//        msg.setShopId(shopId);
//        msg.setStoreId(storeId);
//        rabbitTemplate.convertAndSend(MqDefinition.ORDER_PAY_ROUTING_KEY,msg);



        String  tableId = orderEntity.getTableId();
        tableService.releaseTable(tableId);
        boolean result = this.updateById(orderEntity);
        if(result){
            print(SystemCode.PRINT_BILL,orderEntity,true);
        }

        return result;
    }

    @Override
    public boolean plusDish(PlusDishDTO plusDishDTO) {
        return false;
    }


    @Override
    public CurrentAmountCollectDTO getCurrentCollect(LocalDate start, LocalDate endTime) {
        CurrentAmountCollectDTO result = new CurrentAmountCollectDTO();

        //查询并设置已付款总金额
        QueryWrapper<OrderEntity> totalPayQueryWrapper = new QueryWrapper<>();
        totalPayQueryWrapper.select("sum(pay_amount) as total_amount")
                .lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_PAYED);
        OrderEntity totalPayAmount = this.getOne(totalPayQueryWrapper);
        result.setPayTotal(totalPayAmount!=null?totalPayAmount.getTotalAmount():0);

        //查询并设置已付款总单数
        QueryWrapper<OrderEntity> totalPayCountWrapper = new QueryWrapper<>();
        totalPayCountWrapper.lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_PAYED);
        int totalPayCount = this.count(totalPayCountWrapper);
        result.setPayTotalCount(totalPayCount);

        //查询并设置未付款总金额
        QueryWrapper<OrderEntity> noPayTotalQueryWrapper = new QueryWrapper<>();
        noPayTotalQueryWrapper.select("sum(total_amount) as total_amount")
                .lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_NOPAY);
        OrderEntity noPayTotalAmount = this.getOne(noPayTotalQueryWrapper);
        result.setNoPayTotal(noPayTotalAmount!=null?noPayTotalAmount.getTotalAmount():0);

        //查询并设置未付款总单数
        QueryWrapper<OrderEntity> noPayTotalCountWrapper = new QueryWrapper<>();
        noPayTotalCountWrapper.lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_NOPAY);
        int noPayTotalCount = this.count(noPayTotalCountWrapper);
        result.setNoPayTotalCount(noPayTotalCount);

        //查询并设置已结账就餐人数
        QueryWrapper<OrderEntity> payedTotalPersonQueryWrapper = new QueryWrapper<>();
        payedTotalPersonQueryWrapper.select("sum(person_numbers) as person_numbers")
                .lambda()
                .ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_PAYED);
        OrderEntity payedTotalPerson = this.getOne(payedTotalPersonQueryWrapper);
        result.setTotalPerson(payedTotalPerson!=null?payedTotalPerson.getPersonNumbers():0);

        //查询并设置未结账就餐人数
        QueryWrapper<OrderEntity> notPayTotalPersonQueryWrapper = new QueryWrapper<>();
        notPayTotalPersonQueryWrapper.select("sum(person_numbers) as person_numbers")
                .lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,endTime)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_NOPAY);

        OrderEntity notPayTotalPerson = this.getOne(notPayTotalPersonQueryWrapper);
        result.setCurrentPerson(notPayTotalPerson!=null?notPayTotalPerson.getPersonNumbers():0);
        return result;
    }

    @Override
    public List<CurrentHourCollectDTO> getCurrentHourCollect(LocalDate start, LocalDate end, Integer type) {

        QueryWrapper<OrderEntity> wrapper = new QueryWrapper<>();

        if (type == 1){
            //针对销售额求和
            wrapper.select("SUM(total_amount) as total_amount","HOUR(last_update_time) as current_date_hour")
                    .lambda().ge(OrderEntity::getLastUpdateTime,start)
                    .lt(OrderEntity::getLastUpdateTime,end);
        }

        if (type ==2){
            //针对销售量（单数）求和
            wrapper.select("COUNT(total_amount) as total_amount","HOUR(last_update_time) as current_date_hour")
                    .lambda().ge(OrderEntity::getLastUpdateTime,start)
                    .lt(OrderEntity::getLastUpdateTime,end);

        }

        //针对时间分组汇总
        wrapper.groupBy("current_date_hour").orderByAsc("current_date_hour");
        List<CurrentHourCollectDTO> result = Lists.newArrayList();

        this.list(wrapper).forEach(o->{

            CurrentHourCollectDTO item = new CurrentHourCollectDTO();
            item.setTotalAmount(o.getTotalAmount());
            item.setCurrentDateHour(o.getCurrentDateHour());
            result.add(item);
        });

        //当时间为null，设置值为0
        for(int i=0;i<=23;i++){

            int hour =i;

            if (!result.stream().anyMatch(r->r.getCurrentDateHour() == hour)){

                CurrentHourCollectDTO item = new CurrentHourCollectDTO();
                item.setTotalAmount(0);
                item.setCurrentDateHour(hour);
                result.add(item);
            }
        }

        //对result根据小时从小到大排序
        result.sort((a,b)->Integer.compare(a.getCurrentDateHour(),b.getCurrentDateHour()));

        return result;
    }

    @Override
    public List<PayTypeCollectDTO> getPayTypeCollect(LocalDate start, LocalDate end) {

        List<PayTypeCollectDTO> result = Lists.newArrayList();

        QueryWrapper<OrderViewEntity> wrapper = new QueryWrapper<>();

        wrapper.select("pay_type","SUM(pay_amount) as total_amount")
                .lambda().ge(OrderEntity::getLastUpdateTime,start)
                .lt(OrderEntity::getLastUpdateTime,end)
                .eq(OrderEntity::getPayStatus,SystemCode.ORDER_STATUS_PAYED)
                .groupBy(OrderEntity::getPayType);

        List<OrderViewEntity> orderEntityList = orderViewMapper.selectList(wrapper);

        orderEntityList.forEach(orderEntity -> {

            PayTypeCollectDTO dto = new PayTypeCollectDTO();

            dto.setPayType(orderEntity.getPayType());
            dto.setPayName(PayType.getName(orderEntity.getPayType()));
            dto.setTotalCount(orderEntity.getTotalAmount());
            result.add(dto);
        });

        return result;
    }

    @Override
    public PrivilegeDTO getPrivilegeCollect(LocalDate start, LocalDate end) {

        PrivilegeDTO dto = new PrivilegeDTO();

        QueryWrapper<OrderViewEntity> wrapper = new QueryWrapper<>();

        wrapper.select("SUM(present_amount) as present_amount","SUM(free_amount) as free_amount","SUM(small_amount) AS small_amount")
                .lambda().ge(OrderViewEntity::getLastUpdateTime,start)
                .lt(OrderViewEntity::getLastUpdateTime,end)
                .eq(OrderViewEntity::getPayStatus,SystemCode.ORDER_STATUS_PAYED);

        OrderEntity orderEntity = orderViewMapper.selectOne(wrapper);

        if (orderEntity != null){
            dto.setPresentAmount(orderEntity.getPresentAmount());
            dto.setSmallAmount(orderEntity.getSmallAmount());
            dto.setFreeAmount(orderEntity.getFreeAmount());
        }
        return dto;
    }

    @Override
    public IPage<OrderViewEntity> queryAllOrder(ReceiptDTO receiptDTO){
        IPage<OrderViewEntity> page = new Page<>(receiptDTO.getPage(), receiptDTO.getPageSize());
        QueryWrapper<OrderViewEntity> queryWrapper = new QueryWrapper<>();
        if(receiptDTO.getStartDate()!=null&&receiptDTO.getEndDate()!=null){
            queryWrapper.lambda().between(OrderViewEntity::getCreateTime,receiptDTO.getStartDate(),receiptDTO.getEndDate());
        }
        if(StringUtils.isNotEmpty(receiptDTO.getOperatorName())){
            queryWrapper.lambda().eq(OrderViewEntity::getOperatorName,receiptDTO.getOperatorName());
        }
        if(receiptDTO.getPayType()!=null){
            queryWrapper.lambda().eq(OrderViewEntity::getPayType,receiptDTO.getPayType());
        }
        if(StringUtils.isNotEmpty(receiptDTO.getOrderNumber())){
            queryWrapper.lambda().eq(OrderViewEntity::getOrderNumber,receiptDTO.getOrderNumber());
        }
        queryWrapper.lambda().orderByDesc(OrderViewEntity::getCreateTime).eq(OrderViewEntity::getPayStatus,1);
        return orderViewMapper.selectPage(page, queryWrapper);
    }


    @Override
    public Map<String,Integer>  receiptCount(ReceiptDTO receiptDTO){
        QueryWrapper<OrderViewEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrderViewEntity::getPayStatus,1);
        if(receiptDTO.getStartDate()!=null&&receiptDTO.getEndDate()!=null){
            queryWrapper.lambda().between(OrderViewEntity::getCreateTime,receiptDTO.getStartDate(),receiptDTO.getEndDate());
        }
        if(StringUtils.isNotEmpty(receiptDTO.getOperatorName())){
            queryWrapper.lambda().eq(OrderViewEntity::getOperatorName,receiptDTO.getOperatorName());
        }
        if(receiptDTO.getPayType()!=null){
            queryWrapper.lambda().eq(OrderViewEntity::getPayType,receiptDTO.getPayType());
        }
        if(StringUtils.isNotEmpty(receiptDTO.getOrderNumber())){
            queryWrapper.lambda().eq(OrderViewEntity::getOrderNumber,receiptDTO.getOrderNumber());
        }
        Map<String,Integer> map=new HashMap<>();
        List<OrderViewEntity> orderViewEntityList = orderViewMapper.selectList(queryWrapper);

        int totalAmount=0;
        int payAmount=0;
        for (OrderViewEntity orderViewEntity : orderViewEntityList) {
            if(orderViewEntity.getTotalAmount()!=null){
                totalAmount+= orderViewEntity.getTotalAmount();
            }
            if(orderViewEntity.getPayAmount()!=null){
                payAmount+=orderViewEntity.getPayAmount();
            }
        }
        map.put("totalAmount",totalAmount);
        map.put("payAmount",payAmount);
        return  map;
    }

    @Override
    public List<String> getOperators(){
        QueryWrapper<OrderViewEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("distinct operator_name as operatorName").lambda().isNotNull(OrderViewEntity::getOperatorName);
        return orderViewMapper.selectList(queryWrapper).stream().map(o->o.getOperatorName()).filter(d->d!=null&&!d.trim().equals("")).collect(Collectors.toList());
    }

    @Override
    @Transactional
    @TenantAnnotation
    public String addMicroOrder(OrderEntity orderEntity) {
        //生成订单流水号
        if (StringUtils.isEmpty(orderEntity.getOrderNumber())){
            String storeId = RpcContext.getContext().getAttachment("storeId");
            orderEntity.setOrderNumber(SequenceUtils.getSequence(storeId));
        }
        this.saveOrUpdate(orderEntity);
//        String shopId = RpcContext.getContext().getAttachment("shopId");
//        String storeId = RpcContext.getContext().getAttachment("storeId");

        //操作订单详情
        List<OrderDetailEntity> orderDetailEntities = orderEntity.getOrderDetails();
        if(orderDetailEntities != null){
            orderDetailEntities.forEach(orderDetailEntity -> {
                //统计时候需要知道分类信息
                String categoryName="";
                if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_MORMAL){
                    Dish dish = dishService.getById(orderDetailEntity.getDishId());
                    categoryName = dishCategoryService.getById(dish.getCategoryId()).getName();
                }else if(orderDetailEntity.getDishType()==SystemCode.DISH_TYPE_SETMEAL){
                    Setmeal setmeal = setmealService.getById(orderDetailEntity.getDishId());
                    categoryName = dishCategoryService.getById(setmeal.getCategoryId()).getName();
                }
                orderDetailEntity.setDishCategoryName(categoryName);
                orderDetailEntity.setOrderId(orderEntity.getOrderId());
                orderDetailEntity.setOrderNumber(SequenceUtils.getSequenceWithPrefix(orderEntity.getOrderNumber()));

            });
            orderDetailService.saveBatch(orderDetailEntities);
        }
        return orderEntity.getOrderId();
    }


    /**
     * 前台打印
     * @param orderId
     */
    @Override
    @TenantAnnotation
    public void print(int printType,String orderId,boolean isFront) {
        String shopId = TenantContext.getShopId();
        String storeId = TenantContext.getStorId();
        Print print = new Print();
        print.setShopId(shopId);
        print.setStoreId(storeId);
        print.setFront(isFront);
        print.setPrintOrder(buidPrintOrder(this.getById(orderId)));
        print.setPrintType(printType);
        String printJson = JSON.toJSONString(print);
        log.info("print-info:"+printJson);

        //收银端打印
        rabbitTemplate.convertAndSend(SystemCode.PRINTER_EXCHANGE_NAME, printJson);
    }

    private void printReturnDish(String dishId){
        Print print = new Print();
        print.setPrintType(SystemCode.PRINT_RETURN_DISH);
        print.setFront(false);
        List<String> dishIds = Lists.newArrayList();
        dishIds.add(dishId);

        rabbitTemplate.convertAndSend(SystemCode.PRINTER_EXCHANGE_NAME, JSON.toJSONString(print));
    }

    private PrintOrder buidPrintOrder(OrderEntity orderEntity){
        PrintOrder printOrder = new PrintOrder();
        printOrder.setDishList(new ArrayList<PrinterDish>());
        printOrder.setBillTime(DateTimeUtils.format(orderEntity.getLastUpdateTime()));
        printOrder.setCreateTime(DateTimeUtils.format(orderEntity.getCreateTime()));
        printOrder.setOrderId(orderEntity.getOrderId());
        printOrder.setOrderNumber(orderEntity.getOrderNumber());
        printOrder.setPayAmount(orderEntity.getPayAmount());
        printOrder.setPersonNumber(orderEntity.getPersonNumbers());
        log.info("orderIdIs:"+ orderEntity.getOrderId());
        List<OrderDetailEntity> orderDetails =orderEntity.getOrderDetails();
        //下单后打印支持
        if(orderDetails==null||orderDetails.isEmpty()){
            orderDetails = orderDetailService.getDetailsByOrderId(orderEntity.getOrderId());
        }
        if(orderDetails!=null) {
            orderDetails.forEach(d -> {
                PrinterDish printerDish = new PrinterDish();
                printerDish.setAmount(d.getDishAmount());
                printerDish.setDishName(d.getDishName());
                printerDish.setDishNumber(d.getDishNumber());
                printerDish.setPrice(d.getDishPrice());
                printOrder.getDishList().add(printerDish);
            });
        }
        return printOrder;
    }
}
